// class RightWay { }
// const instance = new RightWay();
// export default instance;

// TODO Strange Way
import icons, { borderIcon, sdfs } from './core/icons';
import { addColoredIcons, COLOR_PRESETS } from './core/utils';

class Singleton {
  private static instance: Singleton;

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }

  private constructor() {}

  private customIcons: Record<string, string> | null = null;

  getIconUrl(name: string): string | null {
    return this.customIcons?.[name] || null;
  }

  async loadDefaultIcons(map: mapboxgl.Map | null) {
    if (!map) return;
    if (this.customIcons !== null) {
      const customIcons = { ...this.customIcons };
      await Promise.all(
        Object.entries(customIcons).map(([name, url]) =>
          this.loadCustomIcon(map, name, url, false),
        ),
      );
    } else {
      this.customIcons = {};
      await Promise.all(
        Object.entries(icons).map(([name, url]) =>
          this.loadCustomIcon(map, name, url),
        ),
      );
      await Promise.all(
        Object.entries(borderIcon.circle).map(([name, url]) =>
          this.loadCustomIcon(map, name, url, true, 'circle'),
        ),
      );
      await Promise.all(
        Object.entries(borderIcon.circle).map(([name, url]) =>
          this.loadCustomIcon(map, `${name}Dark`, url, true, 'circle_dark'),
        ),
      );
      await Promise.all(
        Object.entries(borderIcon.rectangle).map(([name, url]) =>
          this.loadCustomIcon(map, name, url, true, 'roundRect'),
        ),
      );
      await Promise.all(
        Object.entries(borderIcon.rectangle).map(([name, url]) =>
          this.loadCustomIcon(map, `${name}Dark`, url, true, 'roundRect_dark'),
        ),
      );
      // For Test
      await Promise.all(
        Object.entries(sdfs).map(([name, url]) => this.loadSdf(map, name, url)),
      );
    }
  }

  // 加载自定义图标
  async loadCustomIcon(
    map: mapboxgl.Map,
    name: string,
    url: string,
    genColoredImg = true,
    type:
      | 'circle'
      | 'roundRect'
      | 'circle_dark'
      | 'roundRect_dark'
      | null = null,
  ): Promise<void> {
    return new Promise((resolve) => {
      if (!map) return;

      if (map.hasImage(name)) {
        map.removeImage(name);
      }

      map?.loadImage(url, async (err, image) => {
        // be careful cannot load svg
        if (!err && image && this.customIcons) {
          if (map?.hasImage(name) === false) {
            map?.addImage(name, image);
          }
          this.customIcons[name] = url;

          if (genColoredImg) {
            const coloredIcons = await addColoredIcons(
              image as ImageBitmap,
              COLOR_PRESETS,
              0.8,
              type,
            );
            Object.entries(coloredIcons).forEach(
              ([colorName, coloredImage]) => {
                if (colorName.startsWith('dataurl_') && this.customIcons) {
                  this.customIcons[
                    `${name}_${colorName.replace('dataurl_', '')}`
                  ] = coloredImage as string;
                } else {
                  map?.addImage(
                    `${name}_${colorName}`,
                    coloredImage as ImageBitmap,
                  );
                }
              },
            );
          }
        }
        resolve();
      });
    });
  }

  async loadSdf(map: mapboxgl.Map, name: string, url: string): Promise<void> {
    return new Promise((resolve) => {
      if (!map) return;
      if (map.hasImage(name)) {
        map.removeImage(name);
      }
      map?.loadImage(url, async (err, image) => {
        if (!err && image && this.customIcons) {
          if (map?.hasImage(name) === false) {
            map?.addImage(name, image, { sdf: true });
          }
          this.customIcons[name] = url;
        }
        resolve();
      });
    });
  }
}

export default Singleton.getInstance();
